

#ifndef MYRP_LIT_INCLUDED
#define MYRP_LIT_INCLUDED

	#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"	
	#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Shadow/ShadowSamplingTent.hlsl"
	
// Light --------------------------------------
	//此处define作为标识符 用 MAX_VISIBLE_LIGHT 代替16
	#define MAX_VISIBLE_LIGHTS 16 

	
	CBUFFER_START(UnityPerCamera)
		float3 _WorldSpaceCameraPos;
	CBUFFER_END

	CBUFFER_START (UnityPerDraw)
		float4x4 unity_ObjectToWorld;
		float4 unity_LightIndicesOffsetAndCount;
		float4 unity_4LightIndices0, unity_4LightIndices1;
	CBUFFER_END

	CBUFFER_START (UnityPerFrame)
		float4x4 unity_MatrixVP;
	CBUFFER_END


	CBUFFER_START(UnityPerMaterial)
		float4 _MainTex_ST;
		float _CutOff;
	CBUFFER_END

	// Shadow----------------------------
	CBUFFER_START(_ShadowBuffer)
	float4x4 _WorldToShadowMatrices[MAX_VISIBLE_LIGHTS];
	float4x4 _WorldToShadowCascadeMatrices[5];
	float4 _ShadowData[MAX_VISIBLE_LIGHTS];
	float4 _CascadeCullingSpheres[4];
	float _ShadowBias[MAX_VISIBLE_LIGHTS];
	float4 _ShadowMapSize;
	float4 _GlobalShadowData;
	float4 _CascadeShadowMapSize;
	float _CascadeShadowStrength;
	CBUFFER_END

	TEXTURE2D_SHADOW(_ShadowMap);  // Shadow格式纹理
	SAMPLER_CMP(sampler_ShadowMap);  // ShadowMap的采样器
	TEXTURE2D_SHADOW(_CascadeShadowMap);
	SAMPLER_CMP(sampler_CascadeShadowMap);
	TEXTURE2D(_MainTex);
	SAMPLER(sampler_MainTex);

	float InsideCascadedCullSphere(int index,float3 worldPos){
		float4 s =  _CascadeCullingSpheres[index];
		return dot(worldPos-s.xyz,worldPos-s.xyz)<s.w;
	}



	float DistanceToCameraPos(float3 worldPos){
		float3 cameraToFragment = worldPos-_WorldSpaceCameraPos;
		return	dot(cameraToFragment,cameraToFragment);
	}

	float GetHardShadow(float3 pos,bool cascade = false){
		if(cascade)return pos.z>SAMPLE_TEXTURE2D_SHADOW(_CascadeShadowMap,sampler_CascadeShadowMap,pos.xyz)?1:0;
		return pos.z>SAMPLE_TEXTURE2D_SHADOW(_ShadowMap,sampler_ShadowMap,pos.xyz)?1:0;

	}

	float GetSoftShadow(float3 pos,bool cascade = false){
		float attenuation = 0;
		real tenWeights[9];
		real2 tenUVs[9];
		float4 size = cascade?_CascadeShadowMapSize:_ShadowMapSize; 
		SampleShadow_ComputeSamples_Tent_5x5(size,pos.xy,tenWeights,tenUVs);
		attenuation = 0;
		for(int i = 0; i<9;i++){
			attenuation +=tenWeights[i]*GetHardShadow(float3(tenUVs[i].xy,pos.z),cascade);
		};	
		return attenuation;
	}


	float CascadedShadowAttenuation(float3 worldPos){

		#if !defined(_CASCADED_SHADOWS_HARD)&&!defined(_CASCADED_SHADOWS_SOFT)
		return 1.0;
		#endif

		float4 cascadeFlags  = float4(
			InsideCascadedCullSphere(0,worldPos),
			InsideCascadedCullSphere(1,worldPos),
			InsideCascadedCullSphere(2,worldPos),
			InsideCascadedCullSphere(3,worldPos)
		);

		cascadeFlags.yzw = saturate(cascadeFlags.yzw-cascadeFlags.xyz);
	
		float cascadeIndex = 4- dot(cascadeFlags,float4(4,3,2,1));

		float4 shadowpos = mul(_WorldToShadowCascadeMatrices[cascadeIndex],float4(worldPos,1));
		shadowpos.xyz/=shadowpos.w;

	
		

		float attenuation ;
		attenuation =  GetHardShadow(shadowpos,true);
		return lerp(1,attenuation,_CascadeShadowStrength);
	}


	// ���Ǻܶ� https://mp.weixin.qq.com/s/lp0airQqIKdxff4p1EZ3VA 3.2�½� ���ڻ�ȡ��Ӱǿ��
	float ShadowAttenuation(int index,float3 worldPos){

		#if !defined(_SHADOWS_HARD)&&!defined(_SHADOWS_SOFT)
			return 1.0;
		#endif

		if(_ShadowData[index].x<=0||DistanceToCameraPos(worldPos)>_GlobalShadowData.y)return 1;
		float4 shadowPos = mul(_WorldToShadowMatrices[index],float4(worldPos,1.0));
		shadowPos.xyz/=shadowPos.w;
		shadowPos.xy=shadowPos.xy*_GlobalShadowData.x+_ShadowData[index].zw;
		shadowPos.z+=_ShadowBias[index];
		float attenuation =0;
		#if defined(_SHADOWS_HARD)
			#if defined(_SHADOWS_SOFT)
				//dataֵ��yΪ0 ʹ��Ӳ��Ӱ
				if(_ShadowData[index].y==0)
					attenuation = GetHardShadow(shadowPos);
				else 
					attenuation = GetSoftShadow(shadowPos);
			#else 
				attenuation = GetHardShadow(shadowPos);
			#endif
		#else
			attenuation = GetSoftShadow(shadowPos);
		#endif

		return lerp(1,attenuation,_ShadowData[index].x);
	}


	// shadowEnd --------------------------

	#define UNITY_MATRIX_M unity_ObjectToWorld

	//ʵ��������hlsl����
	#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl" 

	CBUFFER_START(_LightBuffer)
		float4 _VisibleLightColors[MAX_VISIBLE_LIGHTS];
		float4 _VisibleLightDirectionOrPosition[MAX_VISIBLE_LIGHTS];
		float4	_VisibleLightAttenuations[MAX_VISIBLE_LIGHTS];
		float4 _VisibleLightSpotDirections[MAX_VISIBLE_LIGHTS];
	CBUFFER_END



	float3 MainLight(float3 normal,float3 worldPos ){
		float shadowAttenuation = CascadedShadowAttenuation(worldPos);
		float3 lightColor = _VisibleLightColors[0].rgb;
		float3 lightDir = _VisibleLightDirectionOrPosition[0].xyz;
		float ndl = saturate(dot(normal,lightDir));
		return ndl*shadowAttenuation*lightColor;
	}

	float3 DiffuseLight(int index ,float3 normal,float3 worldPos,float shadowAttenuation) {

		float4 dirOrPos = _VisibleLightDirectionOrPosition[index];
		float3 lightVector = dirOrPos.xyz-worldPos*dirOrPos.w;
		float3 lightDir = normalize(lightVector) ;
		float3 spotDirection = _VisibleLightSpotDirections[index];
		float diff = saturate(dot(normal,lightDir)); 
		float rangeFade = dot(lightVector,lightVector)*_VisibleLightAttenuations[index].x;
		rangeFade = saturate(1.0-rangeFade*rangeFade);
		rangeFade*=rangeFade;
		
		float spotFade = dot(spotDirection,lightDir);
		spotFade = saturate(spotFade* _VisibleLightAttenuations[index].z+_VisibleLightAttenuations[index].w);
		spotFade *= spotFade;


		float distanceSqr =max(dot(lightVector,lightVector),0.001);
		diff *=  shadowAttenuation*spotFade*rangeFade/distanceSqr ;
		return diff*_VisibleLightColors[index];
	}

// EndLight-----------------------------------



	UNITY_INSTANCING_BUFFER_START(perinstance)	
		UNITY_DEFINE_INSTANCED_PROP(float4,_Color)
	UNITY_INSTANCING_BUFFER_END(perinstance)


	struct VertexInput{
		float4 pos :POSITION;
		float3 normal:NORMAL;
		float2 uv :TEXCOORD0;
		UNITY_VERTEX_INPUT_INSTANCE_ID
	};

	struct VertexOutput{
		float4 clipPos :SV_POSITION;
		float3 normal:TEXCOORD0;
		float3 worldPos:TEXCOORD1;
		float3 vertexLight:TEXCOORD2;
		float2 uv :TEXCOORD3;
		UNITY_VERTEX_INPUT_INSTANCE_ID
	};

	float4 GetNDCCoord(int index,float3 worldPos){
		float4 pos = mul(_WorldToShadowMatrices[index],float4(worldPos,1));
		pos.xyz/=pos.w;
		pos.z = 1- pos.z;
		return pos; 
	}



	VertexOutput LitPassVertex(VertexInput input){

		VertexOutput o;
		UNITY_SETUP_INSTANCE_ID(input);
		UNITY_TRANSFER_INSTANCE_ID(input,o);
		float4 worldPos = mul(UNITY_MATRIX_M, float4(input.pos.xyz, 1.0));
		o.worldPos = worldPos.xyz;
		o.clipPos = mul(unity_MatrixVP,worldPos);
		o.normal=mul((float3x3)UNITY_MATRIX_M,input.normal);
		o.uv = TRANSFORM_TEX(input.uv,_MainTex);
		o.vertexLight=0;
		for(int i = 4; i < min(8,unity_LightIndicesOffsetAndCount.y);i++){
			int lightIndex = unity_4LightIndices1[i-4];
			o.vertexLight += DiffuseLight(lightIndex,o.normal,o.worldPos,1);
		}	
		return o;
	}

	float4 LitPassFragment(VertexOutput input):SV_TARGET{
		UNITY_SETUP_INSTANCE_ID(input);
		
		float4 albedoAlpha = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,input.uv);
		clip(albedoAlpha.a-_CutOff);
		albedoAlpha*= UNITY_ACCESS_INSTANCED_PROP(perinstance,_Color);

		input.normal = normalize(input.normal);
		float3 diffuseLight = input.vertexLight; 

		#if  defined(_CASCADED_SHADOWS_HARD) ||  defined(_CASCADED_SHADOWS_SOFT)
		 diffuseLight+=MainLight(input.normal,input.worldPos);
		#endif
		
		for(int i =0;  i <min(4,unity_LightIndicesOffsetAndCount.y);i++){
			int lightIndex = unity_4LightIndices0[i];
			float shadow = ShadowAttenuation(lightIndex,input.worldPos);
			diffuseLight += DiffuseLight(lightIndex,input.normal,input.worldPos,shadow);
		}

		float3 color = diffuseLight*albedoAlpha.rgb;
		return  float4(color,albedoAlpha.a);
	}

	

	

#endif 